home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 4
/
Amiga Tools 4.iso
/
tools
/
netzwerk
/
parnet
/
sources
/
parnet.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-26
|
8KB
|
398 lines
/*
* PARNET.C
*
*/
#include "defs.h"
#include <resources/misc.h>
#include <hardware/cia.h>
#include <exec/memory.h>
extern func_ptr DeviceVectors[];
extern void (*UnitVectors[])(Iob *, long, long);
extern char DeviceName[];
extern char IdString[];
extern void VInt(void); /* wakeup.asm */
extern Task *VTask; /* wakeup.asm */
extern long VMask; /* wakeup.asm */
extern __stdargs int AutoAllocMiscResource(int, int); /* wakeup.asm */
extern __stdargs int AutoFreeMiscResource(int); /* wakeup.asm */
extern __stdargs int VAddICRVector(int, int, struct Interrupt *); /* wakeup.asm */
extern __stdargs int VRemICRVector(int, int, struct Interrupt *); /* wakeup.asm */
long SysBase = NULL; /* sysbase */
Device *DevBase = NULL; /* device base */
BPTR DevSegment = NULL; /* seglist for device */
long PLock[2] = { 0, 0 }; /* arbitrate network access */
PubPort *StickyPort= NULL;
char ActiveMRPP = 0;
char ActiveMRPB = 0;
char ActiveTask = 0;
char ActiveInt = 0;
struct Interrupt VInterrupt = {
{
NULL, NULL,
NT_INTERRUPT,
-126,
"parnet.device"
},
NULL,
VInt
};
/* Prototyping */
APTR CDevInit(BPTR);
Device *CDevOpen(long,long,Iob *);
long CDevExpunge(void);
BPTR CDevClose(Iob *);
void ReadConfig(void);
void WriteConfig(void);
int DetermineTimeouts(void);
/*
* Init is called when the device is loaded to create it.
*/
APTR
CDevInit(seg)
BPTR seg;
{
Device *db;
SysBase = *(long *)4;
DevBase = db = (Device *)MakeLibrary((long **)DeviceVectors,NULL,NULL,sizeof(Device),NULL);
db->Lib.lib_Node.ln_Type = NT_DEVICE;
db->Lib.lib_Node.ln_Name = DeviceName;
db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
db->Lib.lib_Version = 1;
db->Lib.lib_IdString= (APTR)IdString;
db->ParAddress = 254; /* default address */
db->Port.mp_Node.ln_Type = NT_MSGPORT;
db->Port.mp_SigBit = SIGBREAKB_CTRL_E; /* for VTask */
db->Port.mp_Flags = PA_SIGNAL;
NewList(&db->UnitList);
NewList(&db->Port.mp_MsgList);
ReadConfig();
WriteConfig();
DevSegment = seg;
AddDevice((struct Device *)db);
return((APTR)db);
}
Device *
CDevOpen(unitnum, flags, iob)
long unitnum;
long flags;
Iob *iob;
{
Device *nd = DevBase;
iob->io_Unit = NULL;
LockAddr(PLock); /* because we make calls that kill Forbid() */
nd->Lib.lib_Flags &= ~LIBF_DELEXP;
if (++nd->Lib.lib_OpenCnt == 1) {
/*
* Initial Open, allocate resources
*/
if (AutoAllocMiscResource(MR_PARALLELPORT, -1)) {
iob->io_Actual = PPERR_NOPORTRES;
goto badop;
}
ActiveMRPP = 1;
if (AutoAllocMiscResource(MR_PARALLELBITS, -1)) {
iob->io_Actual = PPERR_NOBITSRES;
goto badop;
}
ActiveMRPB = 1;
VTask = CreateTask("parnet.device", 0, (APTR)ParNetTask, 4096);
if (VTask == NULL) {
iob->io_Actual = PPERR_NOTASK;
goto badop;
}
ActiveTask = 1;
VMask = SIGBREAKF_CTRL_F;
nd->Port.mp_SigTask = VTask; /* for asynchronous I/O */
if (VAddICRVector(0, CIAICRB_FLG, &VInterrupt)) {
iob->io_Actual = PPERR_NOINT;
goto badop;
}
ActiveInt = 1;
if (DetermineTimeouts() < 0) /* couldn't use timer.device */
goto badop;
}
iob->io_Actual= 0;
iob->io_Error = 0;
/*
* Attempt to open the specified unit by protocol
*/
{
short proto = iob->io_Flags & PRO_MASK;
if (proto <= PRO_LAST) {
(*UnitVectors[proto])(iob, unitnum, flags);
if (iob->io_Error == 0) {
UnlockAddr(PLock);
return(nd);
}
}
}
/*
* OPEN FAILED
*/
badop:
CDevClose(iob);
iob->io_Actual = iob->io_Error;
iob->io_Error = IOERR_OPENFAIL;
UnlockAddr(PLock);
return(NULL);
}
long
CDevExpunge(void)
{
Device *nd = DevBase;
BPTR ds = DevSegment;
if (ds == NULL)
Alert(24);
if (nd->Lib.lib_OpenCnt) { /* delayed expunge */
nd->Lib.lib_Flags |= LIBF_DELEXP;
return(NULL);
}
Remove((NODE *)nd);
FreeMem((char *)nd - nd->Lib.lib_NegSize, nd->Lib.lib_NegSize + nd->Lib.lib_PosSize);
DevSegment = NULL;
return(ds);
}
BPTR
CDevClose(iob)
Iob *iob;
{
Device *nd = DevBase;
if (iob->io_Unit)
(*iob->io_Unit->CloseFunc)(iob);
iob->io_Unit = NULL; /* clear vectors */
iob->io_Device = NULL;
if (nd->Lib.lib_OpenCnt == 1) { /* last close */
if (ActiveInt)
VRemICRVector(0, CIAICRB_FLG, &VInterrupt);
if (ActiveTask)
RemTask(VTask);
if (ActiveMRPB)
AutoFreeMiscResource(MR_PARALLELBITS);
if (ActiveMRPP)
AutoFreeMiscResource(MR_PARALLELPORT);
ActiveInt = 0;
ActiveTask= 0;
ActiveMRPB= 0;
ActiveMRPP= 0;
}
if (nd->Lib.lib_OpenCnt && --nd->Lib.lib_OpenCnt)
return(NULL); /* still has refs */
/*
* Note: LIBF_DELEXP never set if DevClose() called from DevOpen()
*/
if (nd->Lib.lib_Flags & LIBF_DELEXP)
return(CDevExpunge()); /* expunge */
return(NULL); /* no expunge */
}
/*
* UNITS
*/
Unit *UnitCache = NULL;
Unit *
FindUnitForPort(port)
uword port;
{
Unit *unit;
Device *db;
if (UnitCache && port == UnitCache->Port)
return(UnitCache);
db = DevBase;
for (unit = (Unit *)db->UnitList.lh_Head; unit != (Unit *)&db->UnitList.lh_Tail; unit = (Unit *)unit->Node.ln_Succ) {
if (port == unit->Port) {
UnitCache = unit;
return(unit);
}
}
return(NULL);
}
Unit *
AllocUnit(iob, beginFunc, abortFunc, dataFunc, closeFunc)
Iob *iob;
func_void beginFunc;
func_void abortFunc;
func_void dataFunc;
func_void closeFunc;
{
Unit *unit = AllocMem(sizeof(Unit), MEMF_CLEAR | MEMF_PUBLIC);
Device *db = DevBase;
unit->BeginIO = beginFunc;
unit->AbortIO = abortFunc;
unit->CloseFunc = closeFunc;
unit->DataFunc = dataFunc;
unit->Port = iob->io_Port;
unit->Protocol = iob->io_Flags & PRO_MASK;
unit->DestAddr = iob->io_Addr;
NewList(&unit->PendIOR);
NewList(&unit->PendIOW);
NewList(&unit->PendCon);
NewList(&unit->PendLsn);
AddHead(&db->UnitList, (struct Node *)unit);
return(unit);
}
void
FreeUnit(unit)
Unit *unit;
{
Remove(&unit->Node);
FreeMem(unit, sizeof(Unit));
UnitCache = NULL;
}
/*
* Packets
*/
Packet *
AllocParPacket(iob, unit, data1, bytes1, data2, bytes2)
Iob *iob;
Unit *unit;
ubyte *data1;
ubyte *data2;
long bytes1;
long bytes2;
{
Packet *packet = AllocMem(sizeof(Packet), MEMF_CLEAR|MEMF_PUBLIC);
packet->iob = iob;
packet->io_Unit = unit;
if (iob)
packet->DestAddr = iob->io_Addr;
packet->DestPort = unit->Port;
packet->Data1 = data1;
packet->Data2 = data2;
packet->DLen1 = bytes1;
packet->DLen2 = bytes2;
return(packet);
}
void
FreeParPacket(packet)
Packet *packet;
{
FreeMem(packet, sizeof(Packet));
}
/*
* CONFIG
*/
void
ReadConfig(void)
{
PubPort *port;
if ((port = StickyPort) == NULL)
port = (PubPort *)FindPort(PORTNAME);
if (port) {
DevBase->ParAddress = port->Address;
ParAddress(DevBase->ParAddress);
/*ParLLTimeout = port->Timeout;*/
}
StickyPort = port;
}
void
WriteConfig(void)
{
char *portName = PORTNAME;
PubPort *port;
if ((port = StickyPort) == NULL && (port = (PubPort *)FindPort(portName)) == NULL) {
port = AllocMem(sizeof(PubPort) + strlen(portName) + 1, MEMF_PUBLIC | MEMF_CLEAR);
port->Port.mp_Node.ln_Name = (char *)(port + 1);
strcpy(port->Port.mp_Node.ln_Name, portName);
port->Port.mp_Node.ln_Type = NT_MSGPORT;
port->Port.mp_Node.ln_Pri = 0;
NewList(&port->Port.mp_MsgList);
AddPort((PORT *)port);
}
port->Address = DevBase->ParAddress;
port->Timeout = ParLLTimeout;
StickyPort = port;
}
/*
* Determines the processor speed for soft wired timeouts in PAR.ASM
* by timing 1 second.
*/
int
DetermineTimeouts(void)
{
IOT iot;
long cnt = 0;
PORT *port = CreatePort(NULL, 0);
if (OpenDevice(TIMERNAME, UNIT_VBLANK, &iot, 0))
return(-1);
iot.tr_node.io_Command = TR_ADDREQUEST;
iot.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
iot.tr_node.io_Message.mn_ReplyPort = port;
iot.tr_time.tv_secs = 1;
iot.tr_time.tv_micro= 0;
SendIO(&iot);
while (CheckIO(&iot) == NULL) {
Time10000();
cnt += 10000;
}
WaitIO(&iot);
ParLLTimeout = cnt;
CloseDevice(&iot);
DeletePort(port);
return(0);
}